﻿using QW.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Reflection;
using System.Collections;
using Microsoft.Extensions.Caching.Memory;

namespace QW.Core.Cache.Memory
{
    /// <summary>
    /// 内存缓存处理器
    /// </summary>
    public class MemoryCacheHandler : BaseCacheHandler, ICacheHandler
    {
        /// <summary>
        /// 标准版缓存本体
        /// </summary>
        private IMemoryCache _ns_cache;
        /// <summary>
        /// .ctor
        /// </summary>
        public MemoryCacheHandler()
        {
            _ns_cache = new MemoryCache(Microsoft.Extensions.Options.Options.Create(new MemoryCacheOptions { ExpirationScanFrequency = new TimeSpan(0, 0, 30) }));  //30秒清理一次过期缓存
        }
        /// <summary>
        /// 缓存总数
        /// </summary>
        /// <returns></returns>
        public int GetCount()
        {
            int result = 0;
            result = GetAllKeys().Count;
            return result;
        }
        /// <summary>
        /// 获取所有的key
        /// <para>会影响性能</para>
        /// </summary>
        /// <returns></returns>
        public List<string> GetAllKeys()
        {
            List<string> result = new List<string>();
            result = GetCacheKeys();
            return result;
        }

        /// <summary>
        /// 获取所有缓存键
        /// </summary>
        /// <returns></returns>
        private List<string> GetCacheKeys()
        {
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
            var entries = _ns_cache.GetType().GetField("_entries", flags).GetValue(_ns_cache);
            var cacheItems = entries as IDictionary;
            var keys = new List<string>();
            if (cacheItems == null) return keys;
            foreach (DictionaryEntry cacheItem in cacheItems)
            {
                keys.Add(cacheItem.Key.ToString());
            }
            return keys;
        }

        /// <summary>
        /// 获得指定键的缓存值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            key = GetFinallyKey(key);
            T result = default(T);
            result = _ns_cache.Get<T>(key);
            return result;
        }

        /// <summary>
        /// 将指定键的对象添加到缓存中，并指定过期时间
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">缓存键</param>
        /// <param name="data">缓存值</param>
        /// <param name="span">缓存过期时间间隔</param>
        /// <param name="isLongTerm">是否长期缓存，长期缓存会不受过期时间影响</param>
        public void Set<T>(string key, T data, TimeSpan? span = null, bool isLongTerm = false)
        {
            key = GetFinallyKey(key);
            var _ct = DateTimeOffset.Now.AddMinutes(DefaultTimeOut);
            if (span.HasValue)
            {
                _ct = DateTimeOffset.Now.Add(span.Value);
            }
            var option = new MemoryCacheEntryOptions { Priority = CacheItemPriority.High };
            if (!isLongTerm)
            {
                option.AbsoluteExpiration = _ct;
            }
            _ns_cache.Set(key, data, option);
        }
        /// <summary>
        /// 获得指定键的缓存值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public List<T> GetList<T>(string key)
        {
            key = GetFinallyKey(key);
            List<T> result = default(List<T>);
            result = _ns_cache.Get<List<T>>(key);
            return result;
        }

        /// <summary>
        /// 将缓存集合存入指定键，并指定过期时间
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">缓存键</param>
        /// <param name="data">缓存值</param>
        /// <param name="span">缓存过期时间间隔</param>
        /// <param name="isLongTerm">是否长期缓存，长期缓存会不受过期时间影响</param>
        public void SetList<T>(string key, IList<T> data, TimeSpan? span = null, bool isLongTerm = false)
        {
            key = GetFinallyKey(key);
            var _ct = DateTimeOffset.Now.AddMinutes(DefaultTimeOut);
            if (span.HasValue)
            {
                _ct = DateTimeOffset.Now.Add(span.Value);
            }
            var option = new MemoryCacheEntryOptions { Priority = CacheItemPriority.High };
            if (!isLongTerm)
            {
                option.AbsoluteExpiration = _ct;
            }
            _ns_cache.Set(key, data, option);
        }
        /// <summary>
        /// 从缓存中移除指定键的缓存值
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {
            key = GetFinallyKey(key);
            _ns_cache.Remove(key);
        }
        /// <summary>
        /// 是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Exists(string key)
        {
            bool result = false;
            key = GetFinallyKey(key);
            object _ = new object();
            result = _ns_cache.TryGetValue(key, out _);
            return result;
        }
    }
}
